/**
 * Copyright (C) 2013 DaiKit.com - daikit-commons module (admin@daikit.com)
 *
 *         Project home : http://code.daikit.com/commons
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.daikit.commons.shared.bean;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.daikit.commons.shared.utils.DkIdGenerator;
import com.daikit.commons.shared.utils.DkStringUtils;


/**
 * The base bean that all beans should extend
 * 
 * @author tcaselli
 * @version $Revision$ Last modifier: $Author$ Last commit: $Date$
 */
public class AbstractDkBeanWithId implements Serializable
{

	private static final long serialVersionUID = -6017186602166046342L;
	protected String id;

	/**
	 * Default Constructor, generate a random ID of length 6
	 */
	public AbstractDkBeanWithId()
	{
		this.id = DkIdGenerator.generateRandomId(6);
	}

	// -------------------------------------------------------------------------------------------
	// ------------ GETTERS / SETTERS
	// -------------------------------------------------------------------------------------------

	/**
	 * @return the id
	 */
	public String getId()
	{
		return id;
	}

	/**
	 * @param id
	 *           the id to set
	 */
	public void setId(final String id)
	{
		this.id = id;
	}

	// -------------------------------------------------------------------------------------------
	// ------------ METHODS
	// -------------------------------------------------------------------------------------------

	protected StringBuilder getToStringBuilder()
	{
		final StringBuilder stringBuilder = new StringBuilder();
		stringBuilder.append("(").append(getClass().getName().substring(getClass().getName().lastIndexOf(".") + 1)).append(":");
		stringBuilder.append("id=").append(getId());
		return stringBuilder;
	}

	protected String finalizeToString(final StringBuilder stringBuilder)
	{
		return stringBuilder.append(")").toString();
	}

	@Override
	public String toString()
	{
		return finalizeToString(getToStringBuilder());
	}

	/**
	 * To be overridden
	 * 
	 * @return a simple representative String of this bean
	 */
	public String getAsSimpleString()
	{
		return getId();
	}

	@Override
	public boolean equals(final Object obj)
	{
		return obj instanceof AbstractDkBeanWithId && id != null && id.equals(((AbstractDkBeanWithId) obj).getId());
	}

	@Override
	public int hashCode()
	{
		return id == null ? super.hashCode() : id.hashCode();
	}

	/**
	 * @param abstractBeanWithId
	 *           the bean to get as simple string
	 * @return an AbstractBeanWithId as simple String (can be null) calling {@link #getAsSimpleString()}
	 */
	public static final String asSimpleString(final AbstractDkBeanWithId abstractBeanWithId)
	{
		return abstractBeanWithId == null ? null : abstractBeanWithId.getAsSimpleString();
	}

	/**
	 * @param list
	 *           a list of {@link AbstractDkBeanWithId}
	 * @return a list of AbstractBeanWithId as simple String
	 */
	public static final String asSimpleString(final List<? extends AbstractDkBeanWithId> list)
	{
		final List<String> temp = new ArrayList<String>();
		for (final AbstractDkBeanWithId bean : list)
		{
			temp.add(bean == null ? null : bean.getAsSimpleString());
		}
		return DkStringUtils.collectionToString(temp);
	}

	/**
	 * @param abstractBeanWithId
	 *           the bean to get ID of
	 * @return the given bean ID or null if bean is null
	 */
	public static final String getId(final AbstractDkBeanWithId abstractBeanWithId)
	{
		return abstractBeanWithId == null ? null : abstractBeanWithId.getId();
	}

	/**
	 * @param abstractBeanWithId
	 *           the bean to get toString
	 * @return an AbstractBeanWithId as String (can be null) calling {@link #toString()}
	 */
	public static final String toString(final AbstractDkBeanWithId abstractBeanWithId)
	{
		return abstractBeanWithId == null ? null : abstractBeanWithId.toString();
	}

	// -------------------------------------------------------------------------------------------
	// ------------ STATIC UTILITY METHODS
	// -------------------------------------------------------------------------------------------

	/**
	 * Get a list of bean as a map, keys are IDs.
	 * 
	 * @param list
	 * @return a map of typed beans extending {@link AbstractDkBeanWithId} with key equal ID
	 */
	public static <X extends AbstractDkBeanWithId> Map<String, X> getBeanCollectionAsMapWithIdKeys(final Collection<X> list)
	{
		final Map<String, X> map = new HashMap<String, X>();
		for (final X x : list)
		{
			map.put(x.getId(), x);
		}
		return map;
	}

	/**
	 * Get a map of bean as a map, keys are map keys and values are map values ids.
	 * 
	 * @param map
	 * @return a map of typed beans extending {@link AbstractDkBeanWithId} with key equal ID
	 */
	public static <X extends AbstractDkBeanWithId> Map<String, String> getBeanMapAsMapWithIdValues(final Map<String, X> map)
	{
		final Map<String, String> ret = new HashMap<String, String>();
		for (final Entry<String, X> entry : map.entrySet())
		{
			final X x = entry.getValue();
			if (x != null)
			{
				ret.put(entry.getKey(), x.getId());
			}
		}
		return ret;
	}

	/**
	 * Get a bean list as a list of IDs.
	 * 
	 * @param list
	 * @return a list of Strings
	 */
	public static <X extends AbstractDkBeanWithId> List<String> getBeanListAsIdsList(final List<X> list)
	{
		final List<String> ret = new ArrayList<String>();
		for (final X x : list)
		{
			ret.add(x.getId());
		}
		return ret;
	}

	/**
	 * Get a bean collection as a set of IDs.
	 * 
	 * @param collection
	 * @return a set of Strings
	 */
	public static <X extends AbstractDkBeanWithId> Set<String> getBeanCollectionAsIdsSet(final Collection<X> collection)
	{
		final Set<String> ret = new HashSet<String>();
		for (final X x : collection)
		{
			ret.add(x.getId());
		}
		return ret;
	}

	/**
	 * Get a bean by its ID in the given collection.
	 * 
	 * @param id
	 * @param collection
	 * @return a typed bean extending {@link AbstractDkBeanWithId}
	 */
	public static <X extends AbstractDkBeanWithId> X getById(final String id, final Collection<X> collection)
	{
		for (final X x : collection)
		{
			if (id.equals(x.getId()))
			{
				return x;
			}
		}
		return null;
	}
}
